//
//  File_System_Manager.cpp
//  LearningOops
//
//  Created by Swetha Patnala on 4/14/13.
//  Copyright (c) 2013 Swetha Patnala. All rights reserved.
//


#include <string>
#include<vector>
#include "File_System_Manager.h"
#include "Disk.h";

using namespace std;

File_System_Manager* File_System_Manager::Instance = NULL;

File_System_Manager* File_System_Manager::getInstance() {
    if (!File_System_Manager::Instance) {
        File_System_Manager::Instance = new File_System_Manager;
    }
    
    return File_System_Manager::Instance;
        
}

File_System_Manager::File_System_Manager() {
    
    
    super_block = new super_block_structure;
    super_block->file_system_name = "cmpe142";
    super_block->num_of_inodes = NUM_OF_INODES;
    super_block->num_of_datablocks = NUM_OF_DATABLOCKS;
    super_block->num_of_unallocated_datablocks = NUM_OF_DATABLOCKS;
    super_block->num_of_unallocated_inodes = NUM_OF_INODES;
    super_block->inode_counter = 0;
    super_block->datablock_counter = 0;
   // cout << "Success";
    
    
    int inode_bitmap[NUM_OF_INODES];
    fill_n(inode_bitmap, NUM_OF_INODES, 0); // initializing all the inodes as free 0 ;
                                            //if any inode is allocated , it would be initialized to 1
    
    int data_bitmap[NUM_OF_DATABLOCKS];
    fill_n(data_bitmap, NUM_OF_DATABLOCKS, 0); // initializing all the datablocks as free 0 ;
                                                //if any datablock is allocated , it would be initialized to 1
    

}

File_System_Manager::~File_System_Manager(){
    
    delete super_block;

}

void File_System_Manager:: printSuperBlock(){
    cout << "Super Block Information"<<endl;
    cout <<" File Name : "<< super_block->file_system_name <<endl;
    cout <<"Total Num of Inodes " << super_block->num_of_inodes <<endl;
    cout <<"Total Num of datablocks " << super_block->num_of_datablocks<<endl;
    cout <<"Num of Unallocated Inodes " << super_block->num_of_unallocated_inodes<<endl;
    cout <<"Num of Unallocated datablocks " << super_block->num_of_unallocated_datablocks<<endl;
    
    
}

void File_System_Manager::printInodeBitMap(){
    
    for(int i =0 ; i < 10 ; i++){
        cout << inode_bitmap[i]<<endl;
    }
    
    
}

void File_System_Manager::printDataBitMap(){
    for(int i =0 ; i < 10 ; i++){
        cout << inode_bitmap[i]<<endl;
    }
    
}

int File_System_Manager:: decrement_inodeblock_num(){
    
    if (super_block->num_of_unallocated_inodes <=  0 ){
        return -1;
    }
    super_block->num_of_unallocated_inodes--;
    return 0;
}

int File_System_Manager:: decrement_datablock_num(int num_of_blocks){
    
    if (super_block->num_of_unallocated_datablocks <=  0){
        return -1;
    }
    
    int num = (super_block->num_of_unallocated_datablocks) - num_of_blocks;
    super_block->num_of_unallocated_datablocks = num;
    return 0;
}

int File_System_Manager::increment_inodecounter(){
    
    if ( super_block->inode_counter >= super_block->num_of_inodes ){
        return -1;
    }
    super_block->inode_counter++;
    //cout<< "Inode counter value" <<super_block->inode_counter<<endl;
    return 0;
}

int File_System_Manager::get_inodecounter(){
     //cout<< "Inode counter value" <<super_block->inode_counter<<endl;
    return (super_block->inode_counter);
}

// method to see if al the inodes are filled
bool File_System_Manager::is_inode_full(){
    if ( super_block->num_of_unallocated_inodes == 0 ){
        return true;
    }
    return false;
    
}


int File_System_Manager::assignValueToInodeBitmap(){
    
    int free_inode = getFreeBitFromInodeBitmap();
    
    if (free_inode== -1){
        return -1;
    }

    inode_bitmap[free_inode] = 1;
    return 0;
    
}



int File_System_Manager::getFreeBitFromInodeBitmap(){
    
    
    
    for (int i=0 ; i < NUM_OF_INODES  ; i++){
        if ( inode_bitmap[i] == 0 ){
            return i;
        }
    }
    return -1;
}



int File_System_Manager::assignValueToDataBitmap(){
    
    int free_datablock = getFreeDataBitFromDataBitmap();
    
    if (free_datablock == -1){
        return -1;
    }
    
    data_bitmap[free_datablock] = 1;
    return 0;
    
}


int File_System_Manager::getFreeDataBitFromDataBitmap(){
    
    
    
    for (int i=0 ; i < NUM_OF_DATABLOCKS  ; i++){
        if ( data_bitmap[i] == 0 ){
            return i;
        }
    }
    return -1;
}


int File_System_Manager::increment_datablock_counter(){
    
    if ( super_block->datablock_counter >= super_block->num_of_inodes ){
        return -1;
    }
    super_block->inode_counter++;
    //cout<< "Inode counter value" <<super_block->inode_counter<<endl;
    return 0;
}

int File_System_Manager::make_fs(char* fileSystem)
{
	if(make_disk(fileSystem))
	{
	if(open_disk(fileSystem))
	{
	std::stringstream temp;
	temp<<super_block->block_number_of_superblock>>"$">>super_block->datablock_counter>>"$">>super_block->file_system_name
			>>"$">>super_block->inode_counter>>"$">>super_block->num_of_datablocks>>"$">>super_block->num_of_inodes>>"$">>
			super_block->num_of_unallocated_datablocks>>"$">>super_block->num_of_unallocated_inodes;
	std::string superblock = temp.str();
	if(block_write(0, (char*)superblock.c_str()))
		return 0;
	else
		return -1;
	close_disk();
	}
	else
		return -1;
	}
	return -1;
}

int File_System_Manager::mount_fs(char* fileSystem )
{
	if(open_disk(fileSystem))
	{
		//reading super block to memory
		std::stringstream superBlock;
		if(block_read(0,(char*)superBlock))
		{
		string element;
		std::vector<std::string> sbValues;

		while(std::getline(superBlock,element,'$'))
		{
			sbValues.push_back(element);
		}

		super_block->block_number_of_superblock = (int)sbValues[0];
		super_block->datablock_counter = (int)sbValues[1];
		super_block->file_system_name = sbValues[2];
		super_block->inode_counter = (int)sbValues[3];
		super_block->num_of_datablocks = (int)sbValues[4];
		super_block->num_of_inodes = (int)sbValues[5];
		super_block->num_of_unallocated_datablocks = (int)sbValues[6];
		super_block->num_of_unallocated_inodes = (int)sbValues[7];
		}
		else
			return -1;

		//reading inode bitmap
		std::stringstream inodeBitmap;
		if(block_read(1,(char*)inodeBitmap))
		{
			string value;
			std::vector<std::string> inBitmap;
			while(std::getline(inodeBitmap,value,'$'))
					{
						inBitmap.push_back(value);
					}
			for(int i=0;i<inBitmap.size();i++)
				inode_bitmap[i] = inBitmap[i];
		}

		//reading data bitmap
		std::stringstream datanodeBitmap;
				if(block_read(2,(char*)datanodeBitmap))
				{
					string node;
					std::vector<std::string> dnBitmap;
					while(std::getline(datanodeBitmap,node,'$'))
							{
								dnBitmap.push_back(node);
							}
					for(int i=0;i<dnBitmap.size();i++)
						data_bitmap[i] = dnBitmap[i];
				}
				else
					return -1;

		//reading inodes
		std::stringstream inode;
		for(int i=3;i<NUM_OF_INODES;i++)
		{
			if(block_read(i,(char*)inode))
			{
			string element;
			std::vector<std::string> inodeElements;
			while(std::getline(inode,element,'$'))
				{
					inodeElements.push_back(element);
				}
			inode_array[i-3]->access_information= inodeElements[0];
			inode_array[i-3]->data_block = inodeElements[1];
			inode_array[i-3]->data_block_addresses = inodeElements[2];
			inode_array[i-3]->file_name = inodeElements[3];
			inode_array[i-3]->inode_number = inodeElements[4];
			inode_array[i-3]->last_access_time = inodeElements[5];
			inode_array[i-3]->last_modification_time = inodeElements[6];
			inode_array[i-3]->mode =inodeElements[7];
			inode_array[i-3]->number_of_blocks_allocated_to_file = inodeElements[8];
			inode_array[i-3]->size_of_file = inodeElements[9];
			inode_array[i-3]->time_of_creation = inodeElements[10];
			return 0;
			}
		}
	}
	else
		return -1;
}

int File_System_Manager::unmount_fs(char* fileSystem)
{
	//writing super block to disk
	if(open_disk(fileSystem))
		{
		std::stringstream sb;
		sb<<super_block->block_number_of_superblock>>"$">>super_block->datablock_counter>>"$">>super_block->file_system_name
				>>"$">>super_block->inode_counter>>"$">>super_block->num_of_datablocks>>"$">>super_block->num_of_inodes>>"$">>
				super_block->num_of_unallocated_datablocks>>"$">>super_block->num_of_unallocated_inodes;
		std::string superblock = sb.str();
		if(!(block_write(0, (char*)superblock.c_str())))
			return -1;
		}
	else
		return -1;

	//writing inode bitmap to disk
	stringstream inbitmap;
	for(int i=0;i<NUM_OF_INODES;i++)
	{
		inbitmap>>inode_bitmap[i];
	}
	string inodebitmap = inbitmap.str();
	if(!(block_write(1,(char*)inodebitmap.c_str())))
		return -1;

	//writing datanode bitmap to disk
	stringstream dnbitmap;
		for(int i=0;i<NUM_OF_DATABLOCKS;i++)
		{
			dnbitmap>>data_bitmap[i];
		}
		string dnodebitmap = dnbitmap.str();
		if(!(block_write(2,(char*)dnodebitmap.c_str())))
			return -1;

	//writing all inodes to disk
		for(int j=0;j<NUM_OF_INODES;j++)
		{
			stringstream in;
			in>>inode_array[j]->access_information>>"$">>inode_array[j]->data_block>>"$">>inode_array[j]->data_block_addresses>>"$"
			>>inode_array[j]->file_name>>"$">>inode_array[j]->inode_number>>"$">>inode_array[j]->last_access_time>>"$"
			>>inode_array[j]->last_modification_time>>"$">>inode_array[j]->mode>>"$">>inode_array[j]->number_of_blocks_allocated_to_file>>"$"
			>>inode_array[j]->size_of_file>>"$">>inode_array[j]->time_of_creation;

			string inodeValues = in.str();

			if(!(block_write(j+3,(char*)inodeValues.c_str())))
				return -1;

			close_disk();
		}
	return 0;
}







